package ifgi.potwc.ipt.ui;

import ifgi.potwc.ipt.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

/**
 * Custom SeekBarPreference. Code based on eample from
 * http://robobunny.com/wp/2011/08/13/android-seekbar-preference/
 * 
 * @author saschak.
 */
public class IptSeekBarPreference extends Preference implements
	OnSeekBarChangeListener
{
    // Tag used for exception handling
    private final String TAG = getClass().getName();

    private static final String ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android";
    private static final String IPT_NAMESPACE = "http://code.google.com/p/ifgipt/";
    
    private static final int DEFAULT_VALUE = 10;

    private int maxValue = 15;
    private int minValue = 5;
    private int interval = 1;
    private int currentValue;
    private String leftUnits = "";
    private String rightUnits = "";
    private SeekBar seekBar;

    private TextView statusText;

    /**
     * Constructor.
     * 
     * @param _context
     * @param _attrs
     */
    public IptSeekBarPreference(Context _context, AttributeSet _attrs)
    {
	super(_context, _attrs);
	initPreference(_context, _attrs);
    }

    /**
     * Initializes the preference.
     * 
     * @param _context
     * @param _attrs
     */
    private void initPreference(Context _context, AttributeSet _attrs)
    {
	setValuesFromXml(_attrs);
	seekBar = new SeekBar(_context, _attrs);
	seekBar.setMax(maxValue - minValue);
	seekBar.setOnSeekBarChangeListener(this);
    }

    /**
     * Sets the values from the preference xml-file.
     * 
     * @param _attrs
     */
    private void setValuesFromXml(AttributeSet _attrs)
    {
	maxValue = _attrs.getAttributeIntValue(ANDROID_NAMESPACE, "max", 15);
	minValue = _attrs.getAttributeIntValue(IPT_NAMESPACE, "min", 5);

	leftUnits = getAttributeStringValue(_attrs, IPT_NAMESPACE,
		"unitsLeft", "");
	String units = getAttributeStringValue(_attrs, IPT_NAMESPACE, "units",
		"");
	rightUnits = getAttributeStringValue(_attrs, IPT_NAMESPACE,
		"unitsRight", units);

	try
	{
	    String newInterval = _attrs.getAttributeValue(IPT_NAMESPACE,
		    "interval");
	    
	    if (newInterval != null)
	    {
		interval = Integer.parseInt(newInterval);
	    }
	}
	catch (Exception e)
	{
	    Log.e(TAG, "Invalid interval value", e);
	}
    }

    /**
     * Returns the value of the specified attribute as a string representation.
     * 
     * @param _attrs
     * @param _namespace
     * @param _name
     * @param _defaultValue
     * @return
     */
    private String getAttributeStringValue(AttributeSet _attrs,
	    String _namespace, String _name, String _defaultValue)
    {
	String value = _attrs.getAttributeValue(_namespace, _name);
	if (value == null)
	{
	    value = _defaultValue;
	}

	return value;
    }

    @Override
    protected View onCreateView(ViewGroup parent)
    {
	RelativeLayout layout = null;

	try
	{
	    LayoutInflater mInflater = (LayoutInflater) getContext()
		    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

	    layout = (RelativeLayout) mInflater.inflate(
		    R.layout.seek_bar_preference, parent, false);
	}
	catch (Exception e)
	{
	    Log.e(TAG, "Error creating seek bar preference", e);
	}

	return layout;
    }

    @SuppressWarnings("deprecation")
    @Override
    public void onBindView(View view)
    {
	super.onBindView(view);

	try
	{
	    // Move our seekbar to the new view we've been given
	    ViewParent oldContainer = seekBar.getParent();
	    ViewGroup newContainer = (ViewGroup) view
		    .findViewById(R.id.seekBarPrefBarContainer);

	    if (oldContainer != newContainer)
	    {
		// Remove the seekbar from the old view
		if (oldContainer != null)
		{
		    ((ViewGroup) oldContainer).removeView(seekBar);
		}
		
		// Remove the existing seekbar (there may not be one) and add
		// ours
		newContainer.removeAllViews();
		newContainer.addView(seekBar,
			ViewGroup.LayoutParams.FILL_PARENT,
			ViewGroup.LayoutParams.WRAP_CONTENT);
	    }
	}
	catch (Exception ex)
	{
	    Log.e(TAG, "Error binding view: " + ex.toString());
	}

	updateView(view);
    }

    /**
     * Update a SeekBarPreference view with our current state
     * 
     * @param view
     */
    protected void updateView(View view)
    {
	try
	{
	    RelativeLayout layout = (RelativeLayout) view;

	    statusText = (TextView) layout.findViewById(R.id.seekBarPrefValue);
	    statusText.setText(String.valueOf(currentValue));
	    statusText.setMinimumWidth(30);

	    seekBar.setProgress(currentValue - minValue);

	    TextView unitsRight = (TextView) layout
		    .findViewById(R.id.seekBarPrefUnitsRight);
	    unitsRight.setText(rightUnits);

	    TextView unitsLeft = (TextView) layout
		    .findViewById(R.id.seekBarPrefUnitsLeft);
	    unitsLeft.setText(leftUnits);
	}
	catch (Exception e)
	{
	    Log.e(TAG, "Error updating seek bar preference", e);
	}
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
	    boolean fromUser)
    {
	int newValue = progress + minValue;

	if (newValue > maxValue)
	{
	    newValue = maxValue;
	}
	else if (newValue < minValue)
	{
	    newValue = minValue;
	}
	else if (interval != 1 && newValue % interval != 0)
	{
	    newValue = Math.round(((float) newValue) / interval) * interval;
	}

	// Change rejected, revert to the previous value
	if (!callChangeListener(newValue))
	{
	    seekBar.setProgress(currentValue - minValue);
	    return;
	}

	// Change accepted, store it
	currentValue = newValue;
	statusText.setText(String.valueOf(newValue));
	persistInt(newValue);
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar)
    {
	// Do nothing
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar)
    {
	// Do nothing
    }

    @Override
    protected Object onGetDefaultValue(TypedArray ta, int index)
    {
	return ta.getInt(index, DEFAULT_VALUE);
    }

    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue)
    {
	if (restoreValue)
	{
	    currentValue = getPersistedInt(currentValue);
	}
	else
	{
	    int temp = 0;
	    try
	    {
		temp = (Integer) defaultValue;
	    }
	    catch (Exception ex)
	    {
		Log.e(TAG, "Invalid default value: " + defaultValue.toString());
	    }

	    persistInt(temp);
	    currentValue = temp;
	}
    }
}